﻿/*************************************************************************************
 * 工    具：  HK_SimpleTaskSystem
 * 
 * 描    述：  HK_SimpleTaskSystem 是一套简易任务管理系统，适用于 `线性任务流程` 的使用场景，支持任务队列的初始化、执行、中断和查询等操作。
 *            该系统使用枚举 (enum) 定义 `任务队列（TaskQueue）` 和 `任务（Task）`，可根据业务需求，自定义任务队列和任务步骤，主要功能如下：
 *            
 *            无外部配置：没有外部配置，在代码中通过枚举定义任务队列和任务；
 *            线性任务队列：任务按顺序执行，适用于按照线性步骤完成的简易任务流程；
 *            指令、查询及事件：
 *              通过指令（Command），初始化/驱动任务队列及任务
 *              通过查询（Query），获取任务队列的进度，或任务队列中所有的任务名
 *              通过事件（Event），监听任务队列及任务的状态变化
 * 
 * 版    本：  V1.7
 * 作    者：  京产肠饭
 * 
 * 创    建：  2024/02/14  V1.0
 * 
 * 更    新：  2024/10/03  V1.1
 *            1.代码优化：系统层代码优化，减少代码冗余
 *            2.功能新增：Debug替换为HKDebug，支持开发期间日志打印
 *            3.Bug修复：InitTaskQueue 时，添加对参数的校验，防止传入空的任务列表
 *            4.代码优化：调整指令层及事件的命名，命名更加直观
 *            
 *            2024/10/04  V1.2
 *            1.功能新增：新增任务队列进度查询 Query_STS_TaskQueue
 *            
 *            2024/11/04  V1.3
 *            1.功能新增：新增编辑器下的 简易任务系统查看器，可在开发环境下，查看当前任务队列及任务完成情况
 *            2.代码优化：修改部分变量及方法名，命名定义更加直观
 *            
 *            2024/11/11  V1.4
 *            1.功能新增：任务的枚举类型可分多个，当同一工程有多个任务流程，方便开发
 *            2.代码优化：当前工具修改较大，引入了多个对泛型的依赖
 *            
 *            2024/11/24  V1.5
 *            1.功能新增：新增任务队列类中的 AllTaskNames，并提供 Query_STS_AllTaskNames 查询方法，方便查询当前队列的所有任务
 *            
 *            2024/12/08  V1.6
 *            1.功能优化：移除 CompleteCurrentTask 和 CompleteAppointTask 对泛型的依赖，减轻使用时的心智负担
 *            
 *            2024/12/24  V1.7
 *            1.代码优化：部分指令重命名，命名更加直观
 *            2.功能优化：任务完成加入延时传参，根据延时时间开始下一个任务
 *            
 * 链   接：   https://gitee.com/JingChanChangFan/hk_-unity-tools
*************************************************************************************/

using System;
using System.Collections.Generic;
using QFramework;

namespace HKTools
{
    /// <summary>  
    /// 简易任务系统接口
    /// </summary>  
    public interface IHK_SimpleTaskSystem : ISystem
    {
        Dictionary<STS_TaskQueueType, STS_QueueDataBase> TaskQueueDic { get; set; }

        void InitTaskQueue<T>(STS_TaskQueueType taskQueueType, Queue<T> taskQueue) where T : Enum;

        void CompleteCurrentTask(STS_TaskQueueType taskQueueType, float delayTime);

        void CompleteAppointTask(STS_TaskQueueType taskQueueType, Enum taskType, float delayTime);

        void BreakUpTaskQueue(STS_TaskQueueType taskQueueType);

        float QueryTaskQueueProgress(STS_TaskQueueType taskQueueType);
    }

    /// <summary>  
    /// 简易任务系统的实现  
    /// </summary>  
    public class HK_SimpleTaskSystem : AbstractSystem, IHK_SimpleTaskSystem
    {
        // 任务队列数据字典
        public Dictionary<STS_TaskQueueType, STS_QueueDataBase> TaskQueueDic { get; set; }

        protected override void OnInit()
        {
            TaskQueueDic = new Dictionary<STS_TaskQueueType, STS_QueueDataBase>();

            this.RegisterEvent<Event_STS_TaskQueueFinish>(args =>
            {
                TaskQueueDic.Remove(args._taskQueueType);
            });

            HKDebug.Log("IHK_SimpleTaskSystem 初始化完成!", LogColor.Cyan, LogStyle.Bold);
        }

        // 初始化任务队列  
        public void InitTaskQueue<T>(STS_TaskQueueType taskQueueType, Queue<T> taskQueue) where T : Enum
        {
            if (TaskQueueDic.ContainsKey(taskQueueType))
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 已经存在，无法重复初始化！");
                return;
            }

            STS_QueueData<T> queueData = new STS_QueueData<T>(taskQueueType, taskQueue);
            TaskQueueDic.Add(taskQueueType, queueData);

            // 发送任务队列开始事件  
            this.SendEvent(new Event_STS_TaskQueueStart(taskQueueType));
        }

        public void CompleteCurrentTask(STS_TaskQueueType taskQueueType, float delayTime)
        {
            if (!TaskQueueDic.ContainsKey(taskQueueType))
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 不存在！");
                return;
            }

            var queueData = TaskQueueDic[taskQueueType];

            if (queueData == null)
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 的任务类型不匹配！");
                return;
            }

            queueData.CompleteCurrentTask(delayTime);
        }

        public void CompleteAppointTask(STS_TaskQueueType taskQueueType, Enum taskType, float delayTime)
        {
            if (!TaskQueueDic.ContainsKey(taskQueueType))
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 不存在！");
                return;
            }

            var queueData = TaskQueueDic[taskQueueType];

            if (queueData == null)
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 的任务类型不匹配！");
                return;
            }

            queueData.CompleteAppointTask(taskType, delayTime);
        }

        public void BreakUpTaskQueue(STS_TaskQueueType taskQueueType)
        {
            if (!TaskQueueDic.ContainsKey(taskQueueType))
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 不存在！");
                return;
            }

            TaskQueueDic.Remove(taskQueueType);

            // 发送任务队列中断事件  
            this.SendEvent(new Event_STS_TaskQueueBreakUp(taskQueueType));
        }

        public float QueryTaskQueueProgress(STS_TaskQueueType taskQueueType)
        {
            if (!TaskQueueDic.ContainsKey(taskQueueType))
            {
                HKDebug.LogWarning($"任务系统：任务队列 {taskQueueType} 不存在！");
                return 0f;
            }

            var queueData = TaskQueueDic[taskQueueType];
            return queueData.TaskProgress;
        }
    }

    /// <summary>  
    /// 任务队列数据的基类  
    /// </summary>  
    public abstract class STS_QueueDataBase : IController
    {
        public STS_TaskQueueType TaskQueueType { get; protected set; }

        public string CurrentTaskName { get; protected set; }

        /// <summary>
        /// 当前队列中，所有的任务
        /// </summary>
        public List<string> AllTaskNames = new List<string>();
        /// <summary>
        /// 当前队列中，待完成的任务
        /// </summary>
        public List<string> PendingTaskNames = new List<string>();
        /// <summary>
        /// 当前队列中，完成的任务
        /// </summary>
        public List<string> FinishedTaskNames = new List<string>();

        public abstract float TaskProgress { get; }

        public abstract void CompleteCurrentTask(float delayTime);

        public abstract void CompleteAppointTask(Enum taskType, float delayTime);

        public IArchitecture GetArchitecture()
        {
            return HK_ArchitectureProvider.Architecture;
        }
    }

    /// <summary>  
    /// 泛型任务队列数据类  
    /// </summary>  
    public class STS_QueueData<T> : STS_QueueDataBase where T : Enum
    {
        Queue<T> taskQueue;
        public Queue<T> TaskQueue
        {
            get
            {
                PendingTaskNames = new List<string>();
                taskQueue.ForEach(task => PendingTaskNames.Add(task.ToString()));

                return taskQueue;
            }
            private set
            {
                taskQueue = value;
            }
        }

        List<T> finishedTaskList;
        public List<T> FinishedTaskList
        {
            get
            {
                FinishedTaskNames = new List<string>();
                finishedTaskList.ForEach(task => FinishedTaskNames.Add(task.ToString()));

                return finishedTaskList;
            }
            private set
            {
                finishedTaskList = value;
            }
        }

        int taskCount;

        T currentTask;
        public T CurrentTask
        {
            get
            {
                return currentTask;
            }
            private set
            {
                currentTask = value;
                CurrentTaskName = currentTask.ToString();
            }
        }

        public override float TaskProgress
        {
            get
            {
                return FinishedTaskList.Count * 1.0f / taskCount;
            }
        }

        public STS_QueueData(STS_TaskQueueType taskQueueType, Queue<T> taskQueue)
        {
            TaskQueueType = taskQueueType;
            TaskQueue = new Queue<T>(taskQueue);
            FinishedTaskList = new List<T>();

            taskCount = taskQueue.Count;

            AllTaskNames = new List<string>();
            PendingTaskNames = new List<string>();

            taskQueue.ForEach(task =>
            {
                AllTaskNames.Add(task.ToString());
                PendingTaskNames.Add(task.ToString());
            });

            ActionKit.DelayFrame(1, () =>
            {
                MoveToNextTask(0);
            }).StartGlobal();
        }

        public override void CompleteCurrentTask(float delayTime)
        {
            if (CurrentTask == null)
            {
                HKDebug.LogWarning($"任务系统：任务队列 {TaskQueueType} 当前没有任务！");
                return;
            }

            FinishedTaskList.Add(CurrentTask);

            // 发送任务完成事件  
            this.SendEvent(new Event_STS_TaskFinish(TaskQueueType, CurrentTask.ToString()));

            MoveToNextTask(delayTime);
        }

        public override void CompleteAppointTask(Enum taskType, float delayTime)
        {
            if (CurrentTask == null)
            {
                HKDebug.LogWarning($"任务系统：任务队列 {TaskQueueType} 当前没有任务！");
                return;
            }

            if (!CurrentTask.Equals(taskType))
            {
                HKDebug.LogWarning($"任务系统：当前任务是 {CurrentTask}，与指定完成的任务 {taskType} 不一致！");
                return;
            }

            CompleteCurrentTask(delayTime);
        }

        void MoveToNextTask(float delayTime)
        {
            if (delayTime <= 0)
            {
                if (TaskQueue.Count > 0)
                {
                    CurrentTask = TaskQueue.Dequeue();

                    // 发送任务开始事件  
                    this.SendEvent(new Event_STS_TaskStart(TaskQueueType, CurrentTask.ToString()));
                }
                else
                {
                    CurrentTask = default;

                    // 发送任务队列完成事件  
                    this.SendEvent(new Event_STS_TaskQueueFinish(TaskQueueType));
                }
            }
            else
            {
                ActionKit.Delay(delayTime, () =>
                {
                    if (TaskQueue.Count > 0)
                    {
                        CurrentTask = TaskQueue.Dequeue();

                        // 发送任务开始事件  
                        this.SendEvent(new Event_STS_TaskStart(TaskQueueType, CurrentTask.ToString()));
                    }
                    else
                    {
                        CurrentTask = default;

                        // 发送任务队列完成事件  
                        this.SendEvent(new Event_STS_TaskQueueFinish(TaskQueueType));
                    }
                }).StartGlobal();
            }
        }
    }
}